package com.itheima.easy.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.itheima.easy.base.PageResponse;
import com.itheima.easy.constant.SuperConstant;
import com.itheima.easy.entity.Resource;
import com.itheima.easy.exception.BaseException;
import com.itheima.easy.mapper.ResourceMapper;
import com.itheima.easy.mapper.RoleMapper;
import com.itheima.easy.mapper.RoleResourceMapper;
import com.itheima.easy.service.ResourceService;
import com.itheima.easy.service.RoleService;
import com.itheima.easy.utils.BeanConv;
import com.itheima.easy.utils.EmptyUtil;
import com.itheima.easy.utils.NoProcessing;
import com.itheima.easy.utils.UserThreadLocal;
import com.itheima.easy.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Description：权限表服务实现类
 */
@Service
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    ResourceMapper resourceMapper;

    @Autowired
    RoleMapper roleMapper;

    @Autowired
    RoleResourceMapper roleResourceMapper;

    @Autowired
    private RoleService roleService;


    @Override
    public PageResponse<ResourceVo> findResourcePage(ResourceVo resourceVo, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        if (!EmptyUtil.isNullOrEmpty(resourceVo.getParentResourceNo())){
            resourceVo.setParentResourceNo(NoProcessing.processString(resourceVo.getParentResourceNo()));
        }
        Page<List<Resource>> page = resourceMapper.selectPage(resourceVo);
        PageResponse<ResourceVo> pageResponse = PageResponse.of(page, ResourceVo.class);
        return pageResponse;
    }

    @Override
    public ResourceVo createResource(ResourceVo resourceVo) {

        if (resourceVo.getResourceType().equals(SuperConstant.MENU)) {
            ResourceVo resourceVo1 = new ResourceVo();
            resourceVo1.setResourceName(resourceVo.getResourceName());
            List<Resource> resources = resourceMapper.selectList(resourceVo1);
            if (resources.size() > 0) {
                throw new BaseException("菜单名称重复");
            }

            ResourceVo resourceVo2 = new ResourceVo();
            resourceVo2.setRequestPath(resourceVo.getRequestPath());
            List<Resource> resources2 = resourceMapper.selectList(resourceVo);
            if (resources2.size() > 0) {
                throw new BaseException("菜单路径重复");
            }
        }
        //转换UserVo为User
        Resource resource = BeanConv.toBean(resourceVo, Resource.class);
        String resourceNo = createResourceNo(resource.getParentResourceNo());
        resource.setResourceNo(resourceNo);
        int flag = resourceMapper.insert(resource);
        if (flag!=1){
            throw new RuntimeException("保存资源信息出错");
        }
        return BeanConv.toBean(resource, ResourceVo.class);
    }

    @Override
    public Boolean updateResource(ResourceVo resourceVo) {
        //转换UserVo为User
        Resource resource = BeanConv.toBean(resourceVo, Resource.class);
        if (resource.getDataState().equals("1")) {
            if (hasChildByMenuId(resource.getResourceNo())) {
                throw new RuntimeException("存在子菜单,不允许禁用");
            }
            if (checkMenuExistRole(resource.getResourceNo())) {
                throw new RuntimeException("菜单已分配,不允许禁用");
            }
        }
        int flag = resourceMapper.updateByPrimaryKeySelective(resource);
        if (flag==0){
            throw new RuntimeException("修改资源信息出错");
        }
        return true;
    }

    @Override
    public List<ResourceVo> findResourceList(ResourceVo resourceVo) {
        List<Resource> resourceList = resourceMapper.selectList(resourceVo);
        return BeanConv.toBeanList(resourceList,ResourceVo.class);
    }

    @Override
    public TreeVo resourceTreeVo(String parentResourceNo, String[] checkedResourceNos, Integer level) {
        //根节点查询树形结构
        List<Resource> resourceList = Lists.newLinkedList();
        //指定节点查询树形结构
        ResourceVo resourceVo = ResourceVo.builder()
            .dataState(SuperConstant.DATA_STATE_0)
            .parentResourceNo(NoProcessing.processString(SuperConstant.ROOT_PARENT_ID))
            .build();
        resourceList.addAll(resourceMapper.selectList(resourceVo));
        if (EmptyUtil.isNullOrEmpty(resourceList)){
            throw new RuntimeException("资源信息为定义！");
        }
        List<TreeItemVo> treeItemVoList  = new ArrayList<>();
        List<String> expandedIds = new ArrayList<>();
        //递归构建树形结构
        List<String> checkedResourceNoList = Lists.newArrayList();
        if (!EmptyUtil.isNullOrEmpty(checkedResourceNos)){
            checkedResourceNoList = Arrays.asList(checkedResourceNos);
        }
        //找根节点
        Resource rootResource =  new Resource();
        rootResource.setResourceNo(SuperConstant.ROOT_PARENT_ID);
        rootResource.setResourceName("智慧养老院");
        //构建树形结构
        recursionTreeItem(treeItemVoList,rootResource,resourceList,checkedResourceNoList,expandedIds, level);
        return TreeVo.builder()
            .items(treeItemVoList)
            .checkedIds(checkedResourceNoList)
            .expandedIds(expandedIds)
            .build();
    }

    private void recursionTreeItem(List<TreeItemVo> treeItemVoList, Resource ResourceRoot, List<Resource> resourceList,
                                   List<String> checkedResourceNos, List<String> expandedIds, Integer level) {
        TreeItemVo treeItem = TreeItemVo.builder()
            .id(ResourceRoot.getResourceNo())
            .label(ResourceRoot.getResourceName())
            .build();
        //判断是否选择
        if (!EmptyUtil.isNullOrEmpty(checkedResourceNos)
            &&checkedResourceNos.contains(ResourceRoot.getResourceNo())){
            treeItem.setIsChecked(true);
        }else {
            treeItem.setIsChecked(false);
        }
        //是否默认展开:如果当前的资源为第二层或者第三层则展开
        if(NoProcessing.processString(ResourceRoot.getResourceNo()).length()/3==2||
           NoProcessing.processString(ResourceRoot.getResourceNo()).length()/3==3){
            expandedIds.add(ResourceRoot.getResourceNo());
        }

        if(NoProcessing.processString(ResourceRoot.getResourceNo()).length()/3 == level + 2){
            return;
        }

        //获得当前资源下子资源
        List<Resource> childrenResource = resourceList.stream()
            .filter(n -> n.getParentResourceNo().equals(ResourceRoot.getResourceNo()) && n.getResourceType().equals(SuperConstant.MENU))
            .collect(Collectors.toList());
        if (!EmptyUtil.isNullOrEmpty(childrenResource)){
            List<TreeItemVo> listChildren  = Lists.newArrayList();

            childrenResource.forEach(n->{
                this.recursionTreeItem(listChildren,n,resourceList,checkedResourceNos,expandedIds, level);});
            treeItem.setChildren(listChildren);
        }

        treeItemVoList.add(treeItem);
    }

    @Override
    public List<MenuVo> menus(String systemCode) {
        Long mgtUserId = UserThreadLocal.getMgtUserId();
        //查询对应角色
        List<RoleVo> roleVoList = roleService.findRoleVoListInUserId(Arrays.asList(mgtUserId));
        List<Long> roleIds = roleVoList.stream().map(RoleVo::getId).collect(Collectors.toList());
//        if (CollUtil.isEmpty(roleIds)) {
//            throw new BaseException("请为用户分配角色和菜单");
//        }
        if (!CollUtil.isEmpty(roleIds)) {
            List<ResourceVo> resources = resourceMapper.findResourceVoListInRoleId(roleIds, SuperConstant.ROOT_PARENT_ID);
            List<MenuVo> list = new ArrayList<>();
            recursionMenuVo(list, resources, SuperConstant.COMPONENT_LAYOUT, roleIds);
            return list;
        }else{
            return new ArrayList<>();
        }
    }

    /**
     * @Description 递归菜单
     */
    public List<MenuVo> recursionMenuVo(List<MenuVo> list, List<ResourceVo> resources, String component, List<Long> roleIds){

        for (ResourceVo resource : resources) {
            List<RoleVo> roleVoList = roleMapper.findRoleVoListByResourceNo(resource.getResourceNo());
            List<String> roleLabels = new ArrayList<>();
            roleVoList.forEach(n->{
                roleLabels.add(n.getLabel());
            });
            MenuMetaVo menuMetaVo = MenuMetaVo.builder()
                .icon(resource.getIcon())
                .roles(roleLabels)
                .title(resource.getResourceName())
                .build();
            MenuVo menuVo = MenuVo.builder()
                .name(resource.getResourceName())
                .hidden(false)
                .component(resource.getRequestPath())
                .meta(menuMetaVo)
                .build();
            if (SuperConstant.COMPONENT_LAYOUT.equals(component)){
                menuVo.setPath("/"+resource.getRequestPath());
                menuVo.setComponent(SuperConstant.COMPONENT_LAYOUT);
            }else {
                menuVo.setPath(resource.getRequestPath());
                menuVo.setComponent(component+"/"+resource.getRequestPath());
            }
//            ResourceVo resourceVoHandler = ResourceVo.builder()
//                .parentResourceNo()
//                .dataState(SuperConstant.DATA_STATE_0)
//                .resourceType(SuperConstant.MENU)
//                .build();

            List<ResourceVo> resourceVos = resourceMapper.findResourceVoListInRoleId(roleIds, resource.getResourceNo());
            if (resourceVos.size()>0){
                menuVo.setRedirect("/"+resource.getResourceName()+"/"+resourceVos.get(0).getResourceName());
                List<MenuVo> listChildren  = new ArrayList<>();
                this.recursionMenuVo(listChildren,resourceVos,resource.getRequestPath(), roleIds);
                menuVo.setChildren(listChildren);
            }
            list.add(menuVo);
        }
        return list;
    }

    @Override
    public List<ResourceVo> findResourceVoListInRoleId(List<Long> roleIds) {
        return resourceMapper.findResourceVoListInRoleId(roleIds, null);
    }

    @Override
    public List<ResourceVo> findResourceVoListByUserId(Long userIdSet) {
        return resourceMapper.findResourceVoListByUserId(userIdSet);
    }

    @Override
    public String createResourceNo(String parentResourceNo) {
        ResourceVo resourceVo = ResourceVo.builder()
            .parentResourceNo(parentResourceNo)
            .build();
        List<Resource> resourceList = resourceMapper.selectList(resourceVo);
        //无下属节点则创建下属节点
        if (EmptyUtil.isNullOrEmpty(resourceList)){
            return NoProcessing.createNo(parentResourceNo,false);
            //有下属节点则累加下属节点
        }else {
            Long resourceNo = resourceList.stream()
                    .map(resource -> { return Long.valueOf(resource.getResourceNo());})
                    .max(Comparator.comparing(i -> i)).get();
            return NoProcessing.createNo(String.valueOf(resourceNo),true);
        }
    }

    @Override
    public int deleteMenuById(String menuId) {
        if (hasChildByMenuId(menuId)) {
            throw new RuntimeException("存在子菜单,不允许删除");
        }
        if (checkMenuExistRole(menuId)) {
            throw new RuntimeException("菜单已分配,不允许删除");
        }
        return resourceMapper.deleteMenuById(menuId);
    }

    @Override
    public List<MenuVo> buttens() {
        Long mgtUserId = UserThreadLocal.getMgtUserId();
        //查询对应角色
        List<RoleVo> roleVoList = roleService.findRoleVoListInUserId(Arrays.asList(mgtUserId));
        List<Long> roleIds = roleVoList.stream().map(RoleVo::getId).collect(Collectors.toList());
        if (CollUtil.isEmpty(roleIds)) {
            throw new BaseException("请为用户分配角色和菜单");
        }
        List<ResourceVo> resources = resourceMapper.findButtonVoListInRoleId(roleIds, SuperConstant.ROOT_PARENT_ID);
        List<MenuVo> list  = new ArrayList<>();
        recursionButtonVo(list,resources,SuperConstant.COMPONENT_LAYOUT, roleIds);
        return list;
    }

    /**
     * @Description 递归菜单
     */
    public List<MenuVo> recursionButtonVo(List<MenuVo> list, List<ResourceVo> resources, String component, List<Long> roleIds){

        for (ResourceVo resource : resources) {
            List<RoleVo> roleVoList = roleMapper.findRoleVoListByResourceNo(resource.getResourceNo());
            List<String> roleLabels = new ArrayList<>();
            roleVoList.forEach(n->{
                roleLabels.add(n.getLabel());
            });
            MenuMetaVo menuMetaVo = MenuMetaVo.builder()
                    .icon(resource.getIcon())
                    .roles(roleLabels)
                    .title(resource.getResourceName())
                    .build();
            MenuVo menuVo = MenuVo.builder()
                    .name(resource.getResourceName())
                    .hidden(false)
                    .component(resource.getRequestPath())
                    .meta(menuMetaVo)
                    .build();
            if (SuperConstant.COMPONENT_LAYOUT.equals(component)){
                menuVo.setPath("/"+resource.getRequestPath());
                menuVo.setComponent(SuperConstant.COMPONENT_LAYOUT);
            }else {
                menuVo.setPath(resource.getRequestPath());
                menuVo.setComponent(component+"/"+resource.getRequestPath());
            }
//            ResourceVo resourceVoHandler = ResourceVo.builder()
//                .parentResourceNo()
//                .dataState(SuperConstant.DATA_STATE_0)
//                .resourceType(SuperConstant.MENU)
//                .build();

            List<ResourceVo> resourceVos = resourceMapper.findButtonVoListInRoleId(roleIds, resource.getResourceNo());
            if (resourceVos.size()>0){
                menuVo.setRedirect("/"+resource.getResourceName()+"/"+resourceVos.get(0).getResourceName());
                List<MenuVo> listChildren  = new ArrayList<>();
                this.recursionButtonVo(listChildren,resourceVos,resource.getRequestPath(), roleIds);
                menuVo.setChildren(listChildren);
            }
            list.add(menuVo);
        }
        return list;
    }


    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean hasChildByMenuId(String menuId) {
        int result = resourceMapper.hasChildByMenuId(menuId);
        return result > 0 ? true : false;
    }

    /**
     * 查询菜单使用数量
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean checkMenuExistRole(String menuId) {
        int result = roleResourceMapper.checkMenuExistRole(menuId);
        return result > 0 ? true : false;
    }

}
